(require 'org)
(require 'org-checklist)
(require 'ox-beamer)
(require 'org-id)
(require 'org-attach)
(custom-set-faces
 '(org-code ((((class color grayscale) (min-colors 88) (background dark)) (:foreground "red"))))
 '(org-todo ((t (:foreground "red" :weight bold)))))
(setq org-todo-keyword-faces
      '(
	("NEXT" . "yellow")
	("HOLD" . "magenta")
	("WAIT" . "RoyalBlue")
	("CANCEL" . "dim gray")
	("DONE" . "gray")
	))

(add-hook 'org-mode-hook 'turn-on-org-cdlatex)
;;;org-mode
;;;
(add-hook 'org-mode-hook 'turn-on-auto-fill)
(add-hook 'org-clock-in-prepare-hook 'my-org-mode-ask-effort)
(defun my-org-mode-ask-effort ()
  "Ask for an effort estimate when clocking in."
  (unless (org-entry-get (point) "Effort")
    (org-set-effort)))
    
(add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
(setq org-hide-leading-stars t)
(setq org-cycle-include-plain-lists t)
(setq org-cycle-include-plain-lists t)
(setq org-cycle-separator-lines 2)
(setq org-tags-column -125)
(setq org-list-demote-modify-bullet
      '(
	("1." . "1)")
	("1)" . "+")
	("+" . "-")
	("-" . "*")
	))
   
(setq org-special-ctrl-a/e t)
(setq org-agenda-use-time-grid nil)
;; (setq org-agenda-todo-list-sublevels nil)
(add-to-list 'org-file-apps '("\\.pdf\\'" . "okular %s"))
(add-to-list 'org-file-apps '("\\.xls\\'" . "libreoffice %s"))
(add-to-list 'org-file-apps '("\\.nb\\'" . "Mathematica %s"))
(add-to-list 'org-file-apps '(directory . "dolphin %s"))
(add-to-list 'org-file-apps '("\\.jpg\\'" . "gwenview %s"))
;; (setq org-agenda-use-time-grid nil)
(setq org-enforce-todo-dependencies t)
(setq org-agenda-dim-blocked-tasks nil)
;; 设置用xelatex 做后端export latex 文件
(setq org-latex-pdf-process '("xelatex %f" "xelatex %f"))
(setq org-beamer-frame-level 3)
(setq org-agenda-restore-windows-after-quit t)
(setq org-catch-invisible-edits 'show)
(setq org-clock-mode-line-total 'current)
(setq org-clock-report-include-clocking-task t)
(setq org-id-link-to-org-use-id t)
(setq org-agenda-clockreport-parameter-plist (quote (:link nil :maxlevel 5 :fileskip0 t :compact t)))
(defun org-summary-todo (n-done n-not-done)
  "Switch entry to DONE when all subentries are done, to TODO otherwise."
  (let (org-log-done org-log-states)   ; turn off logging
    (org-todo (if (= n-not-done 0) "DONE" "TODO"))))

(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)


(setq org-agenda-files (list 
			"~/emacs/org/physics.org"
			"~/emacs/org/refile.org"
			"~/emacs/org/person.org"
			"~/emacs/org/projects"
			"~/emacs/org/review.org"
			"~/emacs/org/play.org"
))
(setq org-attach-directory "~/emacs/org/data/")

(setq org-startup-indented t)
(setq org-cycle-separator-lines 0)
(setq org-agenda-ndays 1)
(define-key global-map "\C-cl" 'org-store-link)
(define-key global-map "\C-ca" 'org-agenda)
(define-key global-map "\C-cr" 'org-capture)

(setq org-log-done '(done))
(setq org-directory "~/emacs/org")
(setq org-default-notes-file (concat org-directory "/note.org"))

(setq org-capture-templates
      '(("t" "Task" entry (file "~/emacs/org/refile.org")
	 "* TODO %?\n  %i  %a")
	("i" "ideas" entry (file "~/emacs/org/refile.org")
	 "* TODO %? :idea:\n %U %a")
	("p" "problem" entry (file "~/emacs/org/refile.org")
	 "* TODO %? :problem:\n %U %a")
	("n" "notes" entry (file "~/emacs/org/refile.org")
	 "* %? :note:\n %U %a")
	("d" "diary" entry (file+headline "~/emacs/org/diary.org" "Diary")
	 "* %t %?")
	))

(setq org-todo-keywords
           '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
	     (sequence "HOLD(h)" "WAIT(w@/!)"  "|" "CANCEL(c@/!)")))

(setq org-todo-state-tags-triggers
      (quote (("CANCEL" ("CANCELLED" . t))
              ("WAIT" ("WAITING" . t))
              ("HOLD" ("WAITING" . t) ("HOLD" . t))
              (done ("WAITING") ("HOLD"))
              ("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
              ("NEXT" ("WAITING") ("CANCELLED") ("HOLD"))
              ("DONE" ("WAITING") ("CANCELLED") ("HOLD")))))
(auto-image-file-mode t)
(setq org-tag-alist '(
;		       (:startgroup . nil)
;		        (:endgroup . nil)

		       ;; (:startgroup . nil)
		       ;; ("discuss" . ?d )
;;		       ("concept". ?c )
		       ;; ("plan" . ?l)
		       ;; ("idea" . ?i)
		       ;; ("note" . ?n)
		       ;; ("ref" . ?r )
		       ;; ("personal" . ?P)
		       ;; (:endgroup . nil)

		       ;; (:startgroup . nil)
		       ;; ("project" . ?p )
		       ;; ("stuck" . ?k )
		       ;; (:endgroup . nil)

		       ;; (:startgroup . nil)
		       ;; ("meson" . ?M )
		       ;; ("baryon" . ?B )
		       ;; (:endgroup . nil)
		       
		       ;; (:startgroup . nil)
		       ;; ("important" . ?n )
		       ;; (:endgroup . nil)
		       ;; ("ARCHIVE" . nil)
		       ;;  ("CP" . ?c)
		       ;;  ("QCD" . ?o)
		       ;;  ("QFT" . ?q)
		       ;;  ("statistic" . ?t)
		       ;; 	("fundamental" . ?f)
		       ;; 	(:newline . nil)
		       ;; 	("charm" .?m)
		       ;; 	("relativistic" .?a)
		       ;; 	("top" .?T)
		       ;; 	("strongDecay" .?S)
		       ;; 	("ewDecay" .?e)
))

(setq org-tag-persistent-alist '(
		       ("urgent" . ?u)
		       ("important" . ?t )
		       ("idea" . ?i)
		       ("note" . ?n)
		       ("question" . ?q)
		       ("PROBLEMS" . ?p)
		       ("ARCHIVE" . nil)
))


(defun yas/org-very-safe-expand ()
  (let ((yas/fallback-behavior 'return-nil)) (yas/expand)))
(add-hook 'org-mode-hook
	  (lambda ()
	    (make-variable-buffer-local 'yas/trigger-key)
	    (setq yas/trigger-key [tab])
	    (add-to-list 'org-tab-first-hook 'yas/org-very-safe-expand)
	    (define-key yas/keymap [tab] 'yas/next-field)))



(add-hook 'org-babel-after-execute-hook 'bh/display-inline-images 'append)

; Make babel results blocks lowercase
(setq org-babel-results-keyword "results")

(defun bh/display-inline-images ()
  (condition-case nil
      (org-display-inline-images)
    (error nil)))
;; --------------------------------------------------------------
;; GTD setup from doc.norang.ca/org-mode.html
;; Agenda parts
(setq org-stuck-projects (quote ("" nil nil "")))
(defun bh/is-project-p ()
  "Any task with a todo keyword subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (forward-line 1)
        (while (and (not has-subtask)
                    (< (point) subtree-end)
                    (re-search-forward "^\*+ " subtree-end t))
          (when (member (org-get-todo-state) org-todo-keywords-1)
            (setq has-subtask t))))
      (and is-a-task has-subtask))))

(defun bh/is-project-subtree-p ()
  "Any task with a todo keyword that is in a project subtree.
Callers of this function already widen the buffer view."
  (let ((task (save-excursion (org-back-to-heading 'invisible-ok)
                              (point))))
    (save-excursion
      (bh/find-project-task)
      (if (equal (point) task)
          nil
        t))))

(defun bh/find-project-task ()
  "Move point to the parent (project) task if any"
  (save-restriction
    (widen)
    (let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
      (while (org-up-heading-safe)
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
          (setq parent-task (point))))
      (goto-char parent-task)
      parent-task)))

(defun bh/is-task-p ()
  "Any task with a todo keyword and no subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (forward-line 1)
        (while (and (not has-subtask)
                    (< (point) subtree-end)
                    (re-search-forward "^\*+ " subtree-end t))
          (when (member (org-get-todo-state) org-todo-keywords-1)
            (setq has-subtask t))))
      (and is-a-task (not has-subtask)))))

(defun bh/is-subproject-p ()
  "Any task which is a subtask of another project"
  (let ((is-subproject)
        (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
    (save-excursion
      (while (and (not is-subproject) (org-up-heading-safe))
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
          (setq is-subproject t))))
    (and is-a-task is-subproject)))

(defun bh/list-sublevels-for-projects-indented ()
  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks.
  This is normally used by skipping functions where this variable is already local to the agenda."
  (if (marker-buffer org-agenda-restrict-begin)
      (setq org-tags-match-list-sublevels 'indented)
    (setq org-tags-match-list-sublevels nil))
  nil)

(defun bh/list-sublevels-for-projects ()
  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks.
  This is normally used by skipping functions where this variable is already local to the agenda."
  (if (marker-buffer org-agenda-restrict-begin)
      (setq org-tags-match-list-sublevels t)
    (setq org-tags-match-list-sublevels nil))
  nil)

(defvar bh/hide-scheduled-and-waiting-next-tasks t)

(defun bh/toggle-next-task-display ()
  (interactive)
  (setq bh/hide-scheduled-and-waiting-next-tasks (not bh/hide-scheduled-and-waiting-next-tasks))
  (when  (equal major-mode 'org-agenda-mode)
    (org-agenda-redo))
  (message "%s WAITING and SCHEDULED NEXT Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "Hide" "Show")))

(defun bh/skip-stuck-projects ()
  "Skip trees that are not stuck projects"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (bh/is-project-p)
          (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
                 (has-next ))
            (save-excursion
              (forward-line 1)
              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t))
                (unless (member "WAITING" (org-get-tags-at))
                  (setq has-next t))))
            (if has-next
                nil
              next-headline)) ; a stuck project, has subtasks but no next task
        nil))))

(defun bh/skip-non-stuck-projects ()
  "Skip trees that are not stuck projects"
  (bh/list-sublevels-for-projects-indented)
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (bh/is-project-p)
          (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
                 (has-next ))
            (save-excursion
              (forward-line 1)
              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t))
                (unless (member "WAITING" (org-get-tags-at))
                  (setq has-next t))))
            (if has-next
                next-headline
              nil)) ; a stuck project, has subtasks but no next task
        next-headline))))

(defun bh/skip-non-projects ()
  "Skip trees that are not projects"
  (bh/list-sublevels-for-projects-indented)
  (if (save-excursion (bh/skip-non-stuck-projects))
      (save-restriction
        (widen)
        (let ((subtree-end (save-excursion (org-end-of-subtree t))))
          (cond
           ((and (bh/is-project-p)
                 (marker-buffer org-agenda-restrict-begin))
            nil)
           ((and (bh/is-project-p)
                 (not (marker-buffer org-agenda-restrict-begin))
                 (not (bh/is-project-subtree-p)))
            nil)
           (t
            subtree-end))))
    (save-excursion (org-end-of-subtree t))))

(defun bh/skip-project-trees-and-habits ()
  "Skip trees that are projects"
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-projects-and-habits-and-single-tasks ()
  "Skip trees that are projects, tasks that are habits, single non-project tasks"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((org-is-habit-p)
        next-headline)
       ((and bh/hide-scheduled-and-waiting-next-tasks
             (member "WAITING" (org-get-tags-at)))
        next-headline)
       ((bh/is-project-p)
        next-headline)
       ((and (bh/is-task-p) (not (bh/is-project-subtree-p)))
        next-headline)
       (t
        nil)))))
(defun org-is-habit-p (&optional pom)
  "Is the task at POM or point a habit?"
  (string= "habit" (org-entry-get (or pom (point)) "STYLE")))
(defun bh/skip-project-tasks-maybe ()
  "Show tasks related to the current restriction.
When restricted to a project, skip project and sub project tasks, habits, NEXT tasks, and loose tasks.
When not restricted, skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
           (next-headline (save-excursion (or (outline-next-heading) (point-max))))
           (limit-to-project (marker-buffer org-agenda-restrict-begin)))
      (cond
       ((bh/is-project-p)
        next-headline)
       ((org-is-habit-p)
        subtree-end)
       ((and (not limit-to-project)
             (bh/is-project-subtree-p))
        subtree-end)
       ((and limit-to-project
             (bh/is-project-subtree-p)
             (member (org-get-todo-state) (list "NEXT")))
        subtree-end)
       (t
        nil)))))

(defun bh/skip-projects-and-habits ()
  "Skip trees that are projects and tasks that are habits"
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-non-subprojects ()
  "Skip trees that are not projects"
  (let ((next-headline (save-excursion (outline-next-heading))))
    (if (bh/is-subproject-p)
        nil
      next-headline)))

(setq org-agenda-custom-commands
      (quote ((" " "Agenda"
               ((agenda "" nil)
		(tags "REFILE"
                      ((org-agenda-overriding-header "Tasks to Refile")
                       (org-tags-match-list-sublevels nil)))
                (tags-todo "-CANCELLED-PROBLEMS/!"
                           ((org-agenda-overriding-header "Stuck Projects")
                            (org-agenda-skip-function 'bh/skip-non-stuck-projects)
                            (org-agenda-sorting-strategy
                             '(priority-down category-keep))))
                (tags-todo "-HOLD-CANCELLED-PROBLEMS/!"
                           ((org-agenda-overriding-header "Projects")
                            (org-agenda-skip-function 'bh/skip-non-projects)
                            (org-agenda-sorting-strategy
                             '(priority-down category-keep))))
                (tags-todo "-CANCELLED/!NEXT"
                           ((org-agenda-overriding-header "Project Next Tasks")
                            (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                            (org-tags-match-list-sublevels t)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(priority-down todo-state-down effort-up category-keep))))
		;; (tags-todo "-REFILE-CANCELLED/!-HOLD-WAITING"
                ;;            ((org-agenda-overriding-header "Tasks")
                ;;             (org-agenda-skip-function 'bh/skip-project-tasks-maybe)
                ;;             (org-agenda-todo-ignore-scheduled t)
                ;;             (org-agenda-todo-ignore-deadlines t)
                ;;             (org-agenda-todo-ignore-with-date t)
                ;;             (org-agenda-sorting-strategy
                ;;              '(category-keep))))
                (tags-todo "-REFILE-CANCELLED-WAITING-REPEAT/!"
                           ((org-agenda-overriding-header (if (marker-buffer org-agenda-restrict-begin) "Project Subtasks" "Standalone Tasks"))
                            (org-agenda-skip-function 'bh/skip-project-tasks-maybe)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-CANCELLED+WAITING/!"
                           ((org-agenda-overriding-header "Waiting and Postponed Tasks")
                            (org-agenda-skip-function 'bh/skip-stuck-projects)
                            (org-tags-match-list-sublevels nil)
                            (org-agenda-todo-ignore-scheduled 'future)
                            (org-agenda-todo-ignore-deadlines 'future)))
;;                (tags "-REFILE/"
;;                       ((org-agenda-overriding-header "Tasks to Archive")
;;                        (org-agenda-skip-function 'bh/skip-non-archivable-tasks)
;;                        (org-tags-match-list-sublevels nil)))
		)
               nil)
              ("s" "Stuck Projects" tags-todo "-CANCELLED-PROBLEMS/!"
               ((org-agenda-overriding-header "Stuck Projects")
                (org-agenda-skip-function 'bh/skip-non-stuck-projects)))
              ("r" "Tasks to Refile" tags "REFILE"
               ((org-agenda-overriding-header "Tasks to Refile")
                (org-tags-match-list-sublevels nil)))
	      ("p" "Projects" tags-todo "-HOLD-CANCELLED-PROBLEMS/!"
               ((org-agenda-overriding-header "Projects")
                (org-agenda-skip-function 'bh/skip-non-projects)
                (org-agenda-sorting-strategy
                 '(category-keep))))
              ("n" "Next Tasks" 
	       ((tags-todo "-WAITING-CANCELLED-REPEAT/!NEXT"
               ((org-agenda-overriding-header "Next Tasks")
                (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                (org-tags-match-list-sublevels t)
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
		(tags-todo "-WAITING-CANCELLED-REPEAT/!NEXT"
               ((org-agenda-overriding-header "Single Next Tasks")
		;; (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                (org-agenda-skip-function 'bh/skip-project-tasks-maybe)
                (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                (org-tags-match-list-sublevels t)
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
		(tags-todo "-WAITING-CANCELLED-REPEAT+question/!"
               ((org-agenda-overriding-header "Question Tasks")
		;; (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                ;; (org-agenda-skip-function 'bh/skip-project-tasks-maybe)
                (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                (org-tags-match-list-sublevels t)
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
		(tags-todo "-REFILE-CANCELLED-REPEAT/!-NEXT-HOLD-WAITING"
		((org-agenda-overriding-header "TODO Tasks")
                (org-agenda-skip-function 'bh/skip-projects-and-habits)
		(org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-sorting-strategy
                 '(category-keep))))
		))
              ("w" "Waiting Tasks"  tags-todo "-CANCELLED+WAITING/!"
               ((org-agenda-overriding-header "Waiting and Postponed tasks"))
               (org-tags-match-list-sublevels nil))
	      ("P" "Problems"
	       ((tags-todo "-CANCELLED-PROBLEMS+question/!"
               ((org-agenda-overriding-header "Questions")
                (org-tags-match-list-sublevels t)))
		(tags-todo "-CANCELLED-question+PROBLEMS/!"
               ((org-agenda-overriding-header "Problems")
                (org-tags-match-list-sublevels t)))
		))
	      ("N" "Notes" tags "note"
               ((org-agenda-overriding-header "Notes")
                (org-tags-match-list-sublevels t)))
              ("A" "Tasks to Archive" tags "-REFILE/"
               ((org-agenda-overriding-header "Tasks to Archive")
                (org-agenda-skip-function 'bh/skip-non-archivable-tasks)
                (org-tags-match-list-sublevels nil))))))
;; ========================================================
;;    Refile setting
;; ========================================================
(setq org-refile-targets (quote ((nil :maxlevel . 2)
				 (("~/emacs/org/note.org") :maxlevel . 1)
                                 (org-agenda-files :maxlevel . 2))))

(setq org-refile-use-outline-path t)

(setq org-outline-path-complete-in-steps nil)

(setq org-refile-allow-creating-parent-nodes (quote confirm))

(setq org-completion-use-ido t)
(setq ido-everywhere t)
(setq ido-max-directory-size 100000)
(ido-mode (quote both))
; Use the current window when visiting files and buffers with ido
(setq ido-default-file-method 'selected-window)
(setq ido-default-buffer-method 'selected-window)
; Use the current window for indirect buffer display
(setq org-indirect-buffer-display 'current-window)

;;;; Refile settings
; Exclude DONE state tasks from refile targets
(defun bh/verify-refile-target ()
  "Exclude todo keywords with a done state and archive heading from refile targets"
  ;; (not (member (nth 2 (org-heading-components)) org-done-keywords)))
  (and 
  (not (member "ARCHIVE" (org-get-tags-at)))
  (not (member (nth 2 (org-heading-components)) org-done-keywords))
  ))

(setq org-refile-target-verify-function 'bh/verify-refile-target)

;; ============================================================
;;   Restrict to current subject in agenda
;; ===================================================
;; Focusing on current work
;;  1. Narrowing to a subtree with Bh/Org-Todo
;;
;;  f5 and S-f5 are bound the functions for narrowing and widening the emacs 
;;    buffer as defined below.
;;  We now use:
;; 
;; T (tasks) for C-c / t on the current buffer
;; N (narrow) narrows to this task subtree
;; U (up) narrows to the immediate parent task subtree without moving
;; P (project) narrows to the parent project subtree without moving
;; F (file) narrows to the current file or file of the existing restriction
;;

;; (global-set-key (kbd "<f5>") 'bh/org-todo)

(defun bh/org-todo (arg)
  (interactive "p")
  (if (equal arg 4)
      (save-restriction
        (bh/narrow-to-org-subtree)
        (org-show-todo-tree nil))
    (bh/narrow-to-org-subtree)
    (org-show-todo-tree nil)))

;; (global-set-key (kbd "<S-f5>") 'bh/widen)

(defun bh/widen ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (org-agenda-remove-restriction-lock)
    (widen)
    (org-agenda-remove-restriction-lock)))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "w" 'bh/widen))
          'append)

(defun bh/restrict-to-file-or-follow (arg)
  "Set agenda restriction to 'file or with argument invoke follow mode.
I don't use follow mode very often but I restrict to file all the time
so change the default 'F' binding in the agenda to allow both"
  (interactive "p")
  (if (equal arg 4)
      (org-agenda-follow-mode)
    (if (equal major-mode 'org-agenda-mode)
        (bh/set-agenda-restriction-lock 4)
      (widen))))

;; (add-hook 'org-agenda-mode-hook
;;           '(lambda () (org-defkey org-agenda-mode-map "F" 'bh/restrict-to-file-or-follow))
;;           'append)

(defun bh/narrow-to-org-subtree ()
  (widen)
  (org-narrow-to-subtree))

(defun bh/narrow-to-subtree ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (org-with-point-at (org-get-at-bol 'org-hd-marker)
        (bh/narrow-to-org-subtree)
        (save-restriction
          (org-agenda-set-restriction-lock)))
    (bh/narrow-to-org-subtree)
    (save-restriction
      (org-agenda-set-restriction-lock))))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "N" 'bh/narrow-to-subtree))
          'append)

(defun bh/narrow-up-one-org-level ()
  (widen)
  (save-excursion
    (outline-up-heading 1 'invisible-ok)
    (bh/narrow-to-org-subtree)))

(defun bh/get-pom-from-agenda-restriction-or-point ()
  (or (org-get-at-bol 'org-hd-marker)
      (and (marker-position org-agenda-restrict-begin) org-agenda-restrict-begin)
      (and (equal major-mode 'org-mode) (point))
      org-clock-marker))

(defun bh/narrow-up-one-level ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (org-with-point-at (bh/get-pom-from-agenda-restriction-or-point)
        (bh/narrow-up-one-org-level))
    (bh/narrow-up-one-org-level)))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "U" 'bh/narrow-up-one-level))
          'append)

(defun bh/narrow-to-org-project ()
  (widen)
  (save-excursion
    (bh/find-project-task)
    (bh/narrow-to-org-subtree)))

(defun bh/narrow-to-project ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (org-with-point-at (bh/get-pom-from-agenda-restriction-or-point)
        (bh/narrow-to-org-project)
        (save-restriction
          (org-agenda-set-restriction-lock)))
    (bh/narrow-to-org-project)
    (save-restriction
      (org-agenda-set-restriction-lock))))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "p" 'bh/narrow-to-project))
          'append)

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "j" 'next-line))
          'append)

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "k" 'previous-line))
          'append)

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "r" 'org-capture))
          'append)

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "a" 'org-agenda-goto-date))
          'append)

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "i" 'org-agenda-clock-in))
          'append)

(add-hook 'org-agenda-mode-hook
          '(lambda ()
	     (org-defkey org-agenda-mode-map "o" 'org-agenda-clock-out)
	     (org-defkey org-agenda-mode-map "c" 'org-agenda-columns)
	     (org-defkey org-agenda-mode-map [tab] 'org-agenda-show-and-scroll-up)
	     (org-defkey org-agenda-mode-map " " 'scroll-up-command)
	     (org-defkey org-agenda-mode-map (kbd "C-SPC") 'scroll-down-command)
	     (org-defkey org-agenda-mode-map "W" 'org-agenda-week-view)
	     )
          'append)



(defvar bh/current-view-project nil)

(defun bh/view-next-project ()
  (interactive)
  (unless (marker-position org-agenda-restrict-begin)
    (goto-char (point-min))
    (setq bh/current-view-project (point)))
  (bh/widen)
  (goto-char bh/current-view-project)
  (forward-visible-line 1)
  (while (and (< (point) (point-max))
              (or (not (org-get-at-bol 'org-hd-marker))
                  (org-with-point-at (org-get-at-bol 'org-hd-marker)
                    (or (not (bh/is-project-p))
                        (bh/is-project-subtree-p)))))
    (forward-visible-line 1))
  (setq bh/current-view-project (point))
  (if (org-get-at-bol 'org-hd-marker)
      (progn
        (bh/narrow-to-project)
        (org-agenda-redo)
        (beginning-of-buffer))
    (beginning-of-buffer)
    (error "All projects viewed.")))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "n" 'bh/view-next-project))
          'append)
;; ===========================================================
;; time counting
;; ===========================================================
;; (setq org-columns-default-format "%25ITEM %TODO %3PRIORITY %TAGS")
(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM %TAGS %TODO")
(setq org-global-properties (quote (("Effort_ALL" . "0:45 1:30 0:15 0:30 1:00 2:00 3:00 4:00 6:00 0:00")
                                    ("STYLE_ALL" . "habit"))))

(setq org-drawers (quote ("PROPERTIES" "CLOCK" "LOGBOOK")))
;; Save clock data and state changes and notes in the LOGBOOK drawer
(setq org-clock-into-drawer t)
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
(setq org-log-into-drawer t)
(setq org-log-state-notes-insert-after-drawers t)
;; Resume clocking task when emacs is restarted
(org-clock-persistence-insinuate)
;; Show lot of clocking history so it's easy to pick items off the C-F11 list
(setq org-clock-history-length 23)
;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)
;; Change tasks to NEXT when clocking in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
;; Save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist t)

;; Change tasks to NEXT when clocking in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
(defun bh/clock-in-to-next (kw)
  "Switch a task from TODO to NEXT when clocking in.
Skips capture tasks, projects, and subprojects.
Switch projects and subprojects from NEXT back to TODO"
  (when (not (and (boundp 'org-capture-mode) org-capture-mode))
    (cond
     ((and (member (org-get-todo-state) (list "TODO"))
           (bh/is-task-p))
      "NEXT")
     ((and (member (org-get-todo-state) (list "NEXT"))
           (bh/is-project-p))
      "TODO"))))

(eval-after-load 'org-list
  '(add-hook 'org-checkbox-statistics-hook (function ndk/checkbox-list-complete)))

(defun ndk/checkbox-list-complete ()
  (save-excursion
    (org-back-to-heading t)
    (let ((beg (point)) end)
      (end-of-line)
      (setq end (point))
      (goto-char beg)
      (if (re-search-forward "\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" end t)
            (if (match-end 1)
                (if (equal (match-string 1) "100%")
                    ;; all done - do the state change
                    (org-todo 'done)
                  (org-todo 'todo))
              (if (and (> (match-end 2) (match-beginning 2))
                       (equal (match-string 2) (match-string 3)))
                  (org-todo 'done)
                (org-todo 'todo)))))))

;; =======================================================================
;; attachment, add new link type att:
;; ======================================================================
(org-add-link-type "att" 'org-attach-open-link)
(defun org-attach-open-link (file &optional in-emacs)
   (org-open-file (expand-file-name file (org-attach-dir t)) in-emacs))
;; completion for attachment
(require 'find-lisp)
(defun org-att-complete-link ()
  "File completion for the \"att\" filetype in `org-mode'."
  (let* ((attach-dir (org-attach-dir nil))
         files file)
    (unless attach-dir
      (error "No attachment dir."))
    (setq files (find-lisp-find-files attach-dir "^[^.].*[^~]$")
          file (org-icompleting-read "Find attachment: "
                                       (mapcar 
                                        (lambda (x) (file-relative-name x attach-dir))
                                        files)
                                       nil t))
    (case org-att-complete-how
      ('full (org-attach-expand-link file))
      ('relative (concat "file:" attach-dir file))
      ('attach (concat "att:" file)))))
(defvar org-att-complete-how 'attach
"Determines how org-att-complete-link completes links to attachments.
It can be the symbols :
- `full' :: A \"file:\" link with full path is returned,
- `relative' :: a \"file:\" link containg a path relative to the directory where the org-file resides is
returned, or
- `attach' :: an \"att:\" link is returned.
`full' is probably best avoided.")

(add-hook 'org-mode-hook
	  '(lambda()
	  (define-key org-mode-map "\C-o" 'org-open-at-point)
	  (define-key org-mode-map "\C-cs" 'org-narrow-to-subtree)
	  (define-key org-mode-map "\M-e" 'org-export)
	  ;; (define-key org-mode-map "\C-c=" 'org-toc-show)
	  (define-key org-mode-map "\C-c," 'org-time-stamp-inactive)
	  (define-key org-mode-map "\M-p" 'outline-previous-visible-heading)
	  (define-key org-mode-map "\M-n" 'outline-next-visible-heading)
	  (define-key org-mode-map (kbd "C-,") 'ace-jump-mode)
	  (define-key org-mode-map (kbd "\C-c\\") 'org-reftex-citation)
	  (define-key org-mode-map (kbd "\C-ci") 'xwp/org-insert-columns-dblock)
	  (define-key org-mode-map (kbd "\C-ce") 'org-set-effort)
	  (define-key org-mode-map (kbd "\C-cp") 'org-set-property)
	  ;; (define-key org-mode-map (kbd "<f10>") 'org-clock-in)
	  (org-defkey org-mode-map "\C-c["    'undefined)
	  (org-defkey org-mode-map "\C-c]"    'undefined)
	  (org-defkey org-mode-map "\C-c;"    'undefined)
	  (org-defkey org-mode-map (kbd "C-'") 'other-window)
	  (org-defkey org-mode-map (kbd "M-<f11>") 'org-attach)
	  (org-defkey org-mode-map (kbd "<f11>") 'xwp/chart-choose)
))


(defun xwp/org-insert-columns-dblock ()
  "Create a dynamic block capturing a column view table."
  (interactive)
  (let ((defaults '(:name "columnview" :hlines 1))
	(id (org-icompleting-read
	     "Capture columns (local, global, entry with :ID: property) [local]: "
	     (append '(("current") ("global"))
		     (mapcar 'list (org-property-values "ID"))))))
    (if (equal id "current") (setq id (org-id-get-create)))
    (if (equal id "global") (setq id 'global))
    (setq defaults (append defaults (list :id id)))
    (org-create-dblock defaults)
    (org-update-dblock)))

(defun xwp/org-clock-default-tasks ()
  (interactive)
  ;; (when (org-clock-is-active)
  ;;   (org-clock-out))
  (let ((defaults '(:name "columnview" :hlines 1))
	 (id (org-icompleting-read
	    "Task: "
	    (append '(("current") ("break") ("movie") ("internet") ("game") ("others") ("computer") ("rest") ("sleep") ("gtd") )))))
    (if (equal id "current") (setq id (if (eq major-mode 'org-mode)
					(org-id-get-create)
					nil)))
    (if (equal id "internet") (setq id "6927bac6-2dc8-46ce-ae3c-5c52a79d7c42"))
    (if (equal id "game") (setq id "981cb11e-b17f-4cb5-934a-f88cdaa2337b"))
    (if (equal id "others") (setq id "006897da-ec69-4bad-8721-89299414e214"))
    (if (equal id "break") (setq id "86a32377-874e-436a-93c7-d54a082786bc"))
    (if (equal id "movie") (setq id "c6ba968e-d2ff-478d-bf32-c36f0536c9ef"))
    (if (equal id "computer") (setq id "e06927a1-92da-4f33-bc12-6719ee62dcd8"))
    (if (equal id "rest") (setq id "7228ef58-d171-4577-a198-ff9ee4e7fc10"))
    (if (equal id "sleep") (setq id "3e892abe-4c99-43b2-ad89-52b5cd770666"))
    (if (equal id "gtd") (setq id "ad9e6762-650b-4fbe-bfc1-9d9298657145"))
    (print id)
    (if (not (eq id nil))
	(let ((idmarker (org-id-find id 'marker)))
	  (org-with-point-at idmarker
	    (save-excursion
	      (save-restriction
		(widen)
		(org-with-point-at idmarker
		  (org-clock-in)
		  )))))
    (message "Not a headline"))))
;; ===================================================================
;; 时间统计和分析 (agenda model f11)
(require 'org-time-analysis)
(setq xwp/org-items-list-day-basic '(
			       ("Movie" "c6ba968e-d2ff-478d-bf32-c36f0536c9ef") 
			       ("Internet" "6927bac6-2dc8-46ce-ae3c-5c52a79d7c42")
			       ("Game"  "981cb11e-b17f-4cb5-934a-f88cdaa2337b")
			       ("Others" "006897da-ec69-4bad-8721-89299414e214")
			       ("Break" "86a32377-874e-436a-93c7-d54a082786bc")
			       ("Computer" "e06927a1-92da-4f33-bc12-6719ee62dcd8")
			       ("Rest" "7228ef58-d171-4577-a198-ff9ee4e7fc10")
			       ("Sleep" "3e892abe-4c99-43b2-ad89-52b5cd770666")
			       ("Gtd" "ad9e6762-650b-4fbe-bfc1-9d9298657145")
			       ))
(setq xwp/org-items-list-week-basic '(
				("Movie" "c6ba968e-d2ff-478d-bf32-c36f0536c9ef") 
				("Internet" "6927bac6-2dc8-46ce-ae3c-5c52a79d7c42")
				("Game"  "981cb11e-b17f-4cb5-934a-f88cdaa2337b")
				("Others" "006897da-ec69-4bad-8721-89299414e214")
				("Computer" "e06927a1-92da-4f33-bc12-6719ee62dcd8")
				))
(setq xwp/project-list '(
			 ("Quantum field" "a46fc420-09f0-47b8-858b-f3adab84696f")
			 ("Rela coupled-channel" "62d3deb0-1f56-4eb3-bdf2-9f9e012b8b0f")
			 ("Relativistic Effect" "385558be-f4e1-4c50-8a0d-01a0dc481c40")
			 ("Health" "27601a56-7bb2-4783-9155-d1a0a9ec97a7")
			 ("English" "6a059e27-aa2d-49f8-abc4-144e6372d66b")
			 ("News" "51774ada-6ab8-42e2-8c55-04419c09a8a8")
			 ))
(setq xwp/org-items-list-day (append xwp/org-items-list-day-basic xwp/project-list))
(setq xwp/org-items-list-week (append xwp/org-items-list-week-basic xwp/project-list))
(provide 'orgmodel)

